Otimizando a Gestão de Preços no Varejo com Python: Aumente sua Lucratividade

Varejo e Atacado
Ciência de Dados
Inteligência Artificial
Autor

Janderson B Abreu

Data de Publicação

22 de outubro de 2024

1. Introdução

A precificação estratégica é uma das principais ferramentas que um varejista possui para influenciar as vendas e maximizar a lucratividade. No mundo do varejo e atacado, onde a concorrência é acirrada e as margens de lucro estão frequentemente sob pressão, a capacidade de ajustar os preços de forma eficaz se torna um diferencial crucial. Segundo Kotler e Keller (2016) , “o preço é um dos mais poderosos instrumentos de marketing e, quando bem utilizado, pode ser a chave para a sobrevivência e o crescimento de uma empresa”.Por outro lado, a precificação manual enfrenta desafios significativos, como a dependência de intuições ou regras de thumb que podem não refletir a realidade do mercado. A otimização de preços baseada em dados não apenas melhora a precisão na definição de preços, mas também proporciona insights sobre a elasticidade da demanda, ajudando os varejistas a maximizar suas margens. Um estudo da McKinsey mostra que empresas que implementam estratégias de precificação baseadas em dados podem ver um aumento de até 20% na lucratividade .


2. Coleta e Preparo de Dados Relevantes

A otimização de preços começa com a coleta de dados relevantes . Vários fatores influenciam o preço ideal de um produto, incluindo:

  • Custos de produção

  • Preços dos concorrentes

  • Demanda do consumidor

  • Sazonalidade

  • Dados demográficos Essas informações podem ser coletadas de diversas fontes, como relatórios internos, pesquisas de mercado e até mesmo através de web scraping . Usar bibliotecas Python como Beautiful Soup permite que os varejistas extraíam automaticamente preços de concorrentes, oferecendo uma visão competitiva do mercado.

    Exemplo de Web Scraping com Beautiful Soup

Aqui está um exemplo de como você pode usar o Beautiful Soup para extrair preços de um site de concorrência:

import requests
from bs4 import BeautifulSoup
import pandas as pd

# URL de exemplo de um site didático
url = 'https://webscraper.io/test-sites/e-commerce/allinone/computers/laptops'

# Fazer a requisição HTTP
resposta = requests.get(url)

# Verificar se a requisição foi bem-sucedida (status code 200)
if resposta.status_code == 200:
    # Análise da página com BeautifulSoup
    sopa = BeautifulSoup(resposta.text, 'html.parser')

    # Encontrar os nomes dos produtos (tags a com a classe title)
    produtos = sopa.find_all('a', class_='title')

    # Encontrar os preços dos produtos (tags h4 com a classe correta)
    precos = sopa.find_all('h4', class_='price')

    # Encontrar as descrições dos produtos (tags p com a classe description)
    descricoes = sopa.find_all('p', class_='description')

    # Encontrar as classificações dos produtos (tags div com a classe ratings)
    classificacoes = sopa.find_all('div', class_='ratings')

    # Verificar se encontramos os dados necessários
    if produtos and precos and descricoes and classificacoes:
        # Preparar lista de dados
        lista_dados = []
        for produto, preco, descricao, classificacao in zip(produtos, precos, descricoes, classificacoes):
            nome_produto = produto.text.strip()
            preco_produto = preco.text.strip()
            descricao_produto = descricao.text.strip()
            
            # Extrair o número de estrelas da classificação
            estrelas = classificacao.find_all('span', class_='glyphicon glyphicon-star')
            num_estrelas = len(estrelas)

            # Extrair o número de reviews
            num_reviews = classificacao.find('p').text.strip()

            # Adicionar os dados à lista
            lista_dados.append({
                'produto': nome_produto,
                'preco': preco_produto,
                'descricao': descricao_produto,
                'classificacao': num_estrelas,
                'num_reviews': num_reviews
            })

        # Criar DataFrame com os dados
        df = pd.DataFrame(lista_dados)

        # Salvar os dados em um arquivo CSV
        df.to_csv('precos_completos.csv', index=False)

        print(f"Arquivo 'precos_completos.csv' criado com sucesso!")

        # Exibir os primeiros 5 produtos para confirmação
        print(df.head())

    else:
        print("Dados insuficientes encontrados.")
else:
    print(f"Erro ao acessar a página. Status code: {resposta.status_code}")
Arquivo 'precos_completos.csv' criado com sucesso!
             produto    preco  \
0   Asus VivoBook...  $295.99   
1  Prestigio Smar...     $299   
2  Prestigio Smar...     $299   
3      Aspire E1-510  $306.99   
4  Lenovo V110-15...  $321.94   

                                           descricao  classificacao  \
0  Asus VivoBook X441NA-GA190 Chocolate Black, 14...              0   
1  Prestigio SmartBook 133S Dark Grey, 13.3" FHD ...              0   
2  Prestigio SmartBook 133S Gold, 13.3" FHD IPS, ...              0   
3    15.6", Pentium N3520 2.16GHz, 4GB, 500GB, Linux              0   
4  Lenovo V110-15IAP, 15.6" HD, Celeron N3350 1.1...              0   

  num_reviews  
0  14 reviews  
1   8 reviews  
2  12 reviews  
3   2 reviews  
4   5 reviews  

Após coletar os dados, a limpeza e manipulação são essenciais. Utilizar a biblioteca Pandas permite que você organize e prepare esses dados para a modelagem, removendo inconsistências e valores ausentes.

Exemplos de Limpeza de Dados com Pandas

import pandas as pd

# Carregar os dados raspados
df = pd.read_csv('precos_completos.csv')

# Verificar as colunas do DataFrame
print("Colunas disponíveis no DataFrame:", df.columns)

# Função para limpar e converter os preços
def limpar_preco(preco):
    # Remover símbolo de moeda e múltiplos valores concatenados
    preco = preco.replace('$', '')  # Remover '$'
    preco = preco.split('$')[0]  # Caso haja múltiplos preços concatenados, pega o primeiro
    try:
        # Converter para float
        return float(preco)
    except ValueError:
        # Caso não seja possível converter, retornar NaN
        return pd.NA

# Aplicar a função de limpeza à coluna de preços
df['preco'] = df['preco'].apply(limpar_preco)

# Remover duplicatas com base nas colunas disponíveis
df = df.drop_duplicates(subset=['produto', 'descricao', 'preco', 'classificacao', 'num_reviews'])

# Preencher valores ausentes de forma inteligente
df['preco'] = df['preco'].fillna(df['preco'].mean())

# Preencher classificações ausentes com a média
if 'classificacao' in df.columns:
    df['classificacao'] = df['classificacao'].fillna(df['classificacao'].mean())

# Preencher número de reviews ausente com 0
if 'num_reviews' in df.columns:
    df['num_reviews'] = df['num_reviews'].fillna(0)

# Verificar o DataFrame limpo
print(df.head())

# Salvar o DataFrame limpo
df.to_csv('precos_limpo.csv', index=False)
Colunas disponíveis no DataFrame: Index(['produto', 'preco', 'descricao', 'classificacao', 'num_reviews'], dtype='object')
             produto   preco  \
0   Asus VivoBook...  295.99   
1  Prestigio Smar...  299.00   
2  Prestigio Smar...  299.00   
3      Aspire E1-510  306.99   
4  Lenovo V110-15...  321.94   

                                           descricao  classificacao  \
0  Asus VivoBook X441NA-GA190 Chocolate Black, 14...              0   
1  Prestigio SmartBook 133S Dark Grey, 13.3" FHD ...              0   
2  Prestigio SmartBook 133S Gold, 13.3" FHD IPS, ...              0   
3    15.6", Pentium N3520 2.16GHz, 4GB, 500GB, Linux              0   
4  Lenovo V110-15IAP, 15.6" HD, Celeron N3350 1.1...              0   

  num_reviews  
0  14 reviews  
1   8 reviews  
2  12 reviews  
3   2 reviews  
4   5 reviews  

3. Modelagem de Preços com Machine Learning

Com os dados prontos, é hora de aplicar algoritmos de aprendizado de máquina para construir modelos de precificação. Métodos como regressão linear , regressão polinomial e Random Forest são algumas das abordagens eficazes.

Exemplo de Regressão Linear

Aqui está um exemplo básico de como implementar uma regressão linear usando a biblioteca Scikit-learn :

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline

# Carregar os dados limpos
df = pd.read_csv('precos_limpo.csv')

# Tratar valores ausentes
df['preco'].fillna(df['preco'].mean(), inplace=True)

# Verifique se as colunas 'rating' e 'num_avaliacoes' estão presentes
if 'rating' in df.columns:
    df['rating'].fillna(df['rating'].mean(), inplace=True)

if 'num_avaliacoes' in df.columns:
    df['num_avaliacoes'].fillna(0, inplace=True)
else:
    df['num_avaliacoes'] = 0  # Ou outra lógica que você preferir

# Ajustar a seleção das variáveis independentes (X) com base nas colunas disponíveis
X_cols = ['classificacao']  # Ajuste aqui com base nas colunas que fazem sentido

X = df[X_cols]
y = df['preco']

# One-hot encoding para variáveis categóricas (por exemplo, 'classificacao')
preprocessador = ColumnTransformer(transformers=[
    ('cat', OneHotEncoder(), ['classificacao'])
], remainder='passthrough')

# Criar pipeline de pré-processamento e modelo
pipeline = Pipeline(steps=[
    ('preprocess', preprocessador),
    ('modelo', LinearRegression())
])

# Dividir em conjunto de treinamento e teste
X_treino, X_teste, y_treino, y_teste = train_test_split(X, y, test_size=0.2, random_state=42)

# Treinar o modelo
pipeline.fit(X_treino, y_treino)

# Fazer previsões
previsoes = pipeline.predict(X_teste)

# Exibir as primeiras 10 previsões e as 10 primeiras linhas do conjunto de teste
print("As primeiras 10 previsões são:", previsoes[:10])
print("\nAs 10 primeiras linhas do conjunto de teste:")
print(X_teste.head(10))
As primeiras 10 previsões são: [912.87774194 912.87774194 912.87774194 912.87774194 912.87774194
 912.87774194 912.87774194 912.87774194 912.87774194 912.87774194]

As 10 primeiras linhas do conjunto de teste:
    classificacao
44              0
4               0
53              0
42              0
10              0
85              0
72              0
94              0
36              0
11              0
/tmp/ipykernel_35161/881320131.py:12: FutureWarning:

A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.
The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.

For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.


A comparação entre diferentes modelos pode ser feita utilizando métricas de performance como RMSE e , permitindo que o varejista escolha o modelo mais eficaz.


4. Implementação e Monitoramento

Após a criação do modelo, a próxima etapa é a implementação . Integrar os modelos de precificação com os sistemas de gestão existentes é essencial para a aplicação prática. Além disso, é fundamental monitorar continuamente o desempenho dos preços.Para isso, dashboards interativos podem ser criados usando bibliotecas como Dash ou Streamlit , permitindo que os gestores visualizem em tempo real as variações de preço e suas consequências nas vendas. Abaixo, apresentamos um exemplo básico de um dashboard em Streamlit:

Exemplo de Dashboard com Streamlit

Salve como app.py e faça: streamlit run app.py no terminal e o resultado sera uma dashboard que analisa produtos em intervalo de preços

import pandas as pd
import streamlit as st
import plotly.express as px

# Carregar os dados limpos
df = pd.read_csv('precos_limpo.csv')

# Tratar valores ausentes
df['preco'] = df['preco'].fillna(df['preco'].mean())

# Streamlit
st.title('Dashboard de Preços')
st.markdown('<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootswatch/4.5.2/united/bootstrap.min.css">', unsafe_allow_html=True)

st.sidebar.header('Filtros')

# Filtro por faixa de preço
preco_min, preco_max = st.sidebar.slider(
    'Selecione a faixa de preço:',
    min_value=float(df['preco'].min()),
    max_value=float(df['preco'].max()),
    value=(float(df['preco'].min()), float(df['preco'].max()))
)

# Filtrar o DataFrame
df_filtrado = df[
    (df['preco'] >= preco_min) & (df['preco'] <= preco_max)
]

# Cards de informações
media_preco = df_filtrado['preco'].mean()
preco_maximo = df_filtrado['preco'].max()
preco_minimo = df_filtrado['preco'].min()

# Cálculos dinâmicos para custo total
custo_total = df_filtrado['preco'].sum()  # Custo total

# Calcular somatória de preços por produto
soma_precos_por_produto = df_filtrado.groupby('produto')['preco'].sum().reset_index()

# Identificar produto mais e menos vendido
produto_mais_vendido = soma_precos_por_produto.loc[soma_precos_por_produto['preco'].idxmax()]['produto'] if not soma_precos_por_produto.empty else 'N/A'
produto_menos_vendido = soma_precos_por_produto.loc[soma_precos_por_produto['preco'].idxmin()]['produto'] if not soma_precos_por_produto.empty else 'N/A'

# Estilizando os cards
st.markdown("""
    <style>
    .card {
        border-radius: 10px;
        padding: 20px;
        margin: 5px; /* Reduzir margem */
        box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
        color: white;
        display: flex;
        justify-content: center;
        align-items: center;
        height: 100px;
        flex-grow: 1;
    }
    .media {background-color: #FFA500;} /* Laranja */
    .maximo {background-color: #28a745;} /* Verde */
    .minimo {background-color: #dc3545;} /* Vermelho */
    .lucro {background-color: #007bff;} /* Azul */
    .mais-vendido {background-color: #17a2b8;} /* Ciano */
    .menos-vendido {background-color: #6f42c1;} /* Roxo */
    </style>
""", unsafe_allow_html=True)

# Layout para os cards ocupando toda a largura
col1, col2, col3 = st.columns([1, 1, 1])
with col1:
    st.markdown(f'<div class="card media">Média de Preço: R$ {media_preco:.2f}</div>', unsafe_allow_html=True)
with col2:
    st.markdown(f'<div class="card maximo">Preço Mais Alto: R$ {preco_maximo:.2f} ▲</div>', unsafe_allow_html=True)
with col3:
    st.markdown(f'<div class="card minimo">Preço Mais Baixo: R$ {preco_minimo:.2f} ▼</div>', unsafe_allow_html=True)

# Novos cards
col4, col5, col6 = st.columns([1, 1, 1])
with col4:
    st.markdown(f'<div class="card lucro">Custo Total: R$ {custo_total:.2f}</div>', unsafe_allow_html=True)
with col5:
    st.markdown(f'<div class="card mais-vendido">Produto Mais Vendido: {produto_mais_vendido}</div>', unsafe_allow_html=True)
with col6:
    st.markdown(f'<div class="card menos-vendido">Produto Menos Vendido: {produto_menos_vendido}</div>', unsafe_allow_html=True)

# Exibir resultados
st.write("Resultados filtrados:")
st.dataframe(df_filtrado)

# Gráficos
st.subheader("Distribuição de Preços e Contagem por Classificação")

# Layout para os gráficos ocupando toda a largura
col7, col8 = st.columns([1, 1])

with col7:
    st.bar_chart(df_filtrado['preco'], use_container_width=True)
with col8:
    classificacao_contagem = df_filtrado['classificacao'].value_counts()
    st.bar_chart(classificacao_contagem, use_container_width=True)

# Gráfico de Boxplot
st.subheader("Análise Gráfica")
fig_box = px.box(df_filtrado, y='preco', title='Boxplot de Preços')
st.plotly_chart(fig_box, use_container_width=True)

A criação de um dashboard não só facilita a visualização dos dados, mas também permite a tomada de decisões rápidas e informadas. Assim, os varejistas podem ajustar preços em tempo real com base no desempenho de vendas e na concorrência.


5. Conclusão

A otimização de preços baseada em dados é um caminho eficaz para aumentar a lucratividade e a competitividade no mercado. Com a combinação certa de coleta de dados, modelagem preditiva e monitoramento contínuo, os varejistas podem não apenas responder às flutuações do mercado, mas também antecipá-las. Ao implementar essas técnicas, os varejistas estão melhor posicionados para maximizar suas margens de lucro e melhorar a satisfação do cliente.Como afirma Baker (2018) , “um preço bem definido é mais do que apenas um número; é uma estratégia que pode influenciar o comportamento do consumidor e impulsionar as vendas”.


Referências

  1. Baker, M. J. (2018). Marketing Strategy and Management. Palgrave Macmillan.

  2. Kotler, P., & Keller, K. L. (2016). Marketing Management. Pearson.

  3. McKinsey & Company. (2020). Pricing Excellence: How to Boost Profitability.

  4. Davenport, T. H. (2013). Analytics at Work: Smarter Decisions, Better Results. Harvard Business Review Press.